﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mimoza.Common;

namespace Mimoza.ObjectLayer
{
    public class ContainerRepository
    {
        private OL ol;
        const string c_RootContainerId = "83399760-cc66-44f6-b108-d4991978e364";
        const string c_DefaultHostContainer = "83399760-CC66-44f6-B108-D4991978E366";

        public ContainerRepository(OL ol)
        {
            this.ol = ol;
            this.ol.DBLayer.DBContainerRepository.OnObjectChanged += DBObjectChangedEventHandler;
        }

        public event EventHandler<ObjectLayer_ObjectChangedEventArgs> OnObjectChanged;
        private void RaiseOnObjectChanged(ObjectLayer_ObjectChangedEventArgs e)
        {
            EventHandler<ObjectLayer_ObjectChangedEventArgs> handler = OnObjectChanged;

            if (handler != null)
            {
                handler(this, e);
            }
        }
        void DBObjectChangedEventHandler(object sender, DBObjectChangedEventArgs e)
        {
            ObjectLayerEventType type = ObjectLayerEventType.ObjectInserted;
            Object obj;
            switch (e.EventType)
            {
                case DBEventType.ObjectInserted:
                    type = ObjectLayerEventType.ObjectInserted;
                    break;
                case DBEventType.ObjectUpdated:
                    type = ObjectLayerEventType.ObjectUpdated;
                    break;
                case DBEventType.ObjectDeleted:
                    type = ObjectLayerEventType.ObjectDeleted;
                    break;
            }

            obj = this.CreateContainer(e.Object as ContainerRecord);
            ObjectLayer_ObjectChangedEventArgs args = new ObjectLayer_ObjectChangedEventArgs(obj, type);

            RaiseOnObjectChanged(args);
        }


        public Container CreateContainer()
        {
            return new Container(ol);
        }
        public Container CreateContainer(ContainerRecord record)
        {
            return new Container(ol, record);
        }
        public Container CreateContainerByID(Guid ContainerID)
        {
            ContainerRecord record = new ContainerRecord();
            record.ID = ContainerID;
            return new Container(ol, record);
        }

        public Container RootContainer
        {
            get { return GetContainerByID(new Guid(c_RootContainerId)); }
        }
        public Container CreateRootContainer()
        {
            return CreateContainerByID(new Guid(c_RootContainerId));
        }
        public Container DefaultHostContainer
        {
            get { return GetContainerByID(new Guid(c_DefaultHostContainer)); }
        }

        public Container GetContainerByID(Guid ContainerID)
        {
            ContainerRecord record = ol.DBLayer.DBContainerRepository.GetContainer(ContainerID);
            if ( record == null ) return null;
            return new Container(ol, record);
        }

        public void Add(Container container)
        {
            ol.DBLayer.DBContainerRepository.Insert(container.Record);
        }
        public void Delete(Container container)
        {
            ol.DBLayer.DBContainerRepository.Delete(container.Record);
        }
        public void Update(Container container)
        {
            ol.DBLayer.DBContainerRepository.Update(container.Record);
        }

        public IEnumerable<Container> GetChilds(Container container)
        {
            foreach (ContainerRecord record in ol.DBLayer.DBContainerRepository.GetChildsContainer(container.ID))
            {
                yield return new Container(ol, record);
            }
        }
        public IEnumerable<Policy> GetDirectPolicy(Container container)
        {
            foreach (PolicyRecord record in ol.DBLayer.DBContainerRepository.GetPolicies(container.ID))
            {
                yield return new Policy(ol, record);
            }
        }
        public IEnumerable<Policy> GetInDirectPolicy(Container container)
        {
            do
            {
                container = container.Parent;
                if (container == null)
                {
                    yield break;
                }
                foreach (Policy policy in GetDirectPolicy(container))
                {
                    yield return policy;
                }
            } while (true);
        }
        public IEnumerable<Policy> GetEffectivePolicy(Container container)
        {
            List<Policy> effectivePolicies = new List<Policy>();
            
            List<Policy> inDirectPolicies = new List<Policy>(GetInDirectPolicy(container));
            List<Policy> directPolicies = new List<Policy>(GetDirectPolicy(container));
            List<Policy> policies = directPolicies;
            policies.AddRange(inDirectPolicies); // back order

            foreach (Policy policy in policies)
            {
                if (!policy.IsEnabled) continue;

                Policy effectivePolicy = effectivePolicies.Find(p => p.PluginID==policy.PluginID);
                if (effectivePolicy!=null)
                {
                    if (policy.Override)
                    {
                        effectivePolicies.Remove(effectivePolicy);
                        effectivePolicies.Add(policy);
                    }
                    else
                    {
                        if (effectivePolicy.IsMultiple && policy.IsMultiple)
                        {
                            effectivePolicies.Add(policy);
                        }
                    }
                }
                else
                {
                    effectivePolicies.Add(policy);
                }
            }

            Common.Logger.Log.Info("ContainerRepository.GetEffectivePolicy inDirectPolicies.size - " + 
                inDirectPolicies.Count.ToString() +
                " directPolicies.size - " + directPolicies.Count.ToString() + " effectivePolicies.size - " +
                effectivePolicies.Count.ToString() + ".");

            return effectivePolicies;
        }
        public IEnumerable<Host> GetHosts(Container container)
        {
            foreach (HostRecord record in ol.DBLayer.DBContainerRepository.GetHosts(container.ID))
            {
                yield return new Host(ol, record);
            }
        }
    }
}
